<?php

namespace fakis\core\base;

use Yii;
use yii\base\InvalidConfigException;

/**
 * 服务
 *
 * @property array $providers 服务提供者
 *
 * @author Fakis <fakis738@qq.com>
 */
class Service extends \yii\base\Component
{
    /**
     * @var Service[]
     */
    private array $_services = [];

    /**
     * @var array
     */
    private array $_providers = [];

    /**
     * @param array $config
     * @throws InvalidConfigException
     */
    public function __construct($config = [])
    {
        $this->setProviders($this->providers());
        parent::__construct($config);
    }

    /**
     * 初始化服务提供者
     * @return array
     */
    public function providers(): array
    {
        return [];
    }

    /**
     * 返回服务提供者
     * @return array
     */
    public function getProviders(): array
    {
        return $this->_providers;
    }

    /**
     * 设置服务提供者
     * @param array $providers
     * @throws InvalidConfigException
     */
    public function setProviders(array $providers)
    {
        foreach ($providers as $id => $provider) {
            unset($this->_services[$id]);

            if ($provider === null) {
                unset($this->_providers[$id]);
                return;
            }

            if (is_object($provider) || is_callable($provider, true)) {
                // an object, a class name, or a PHP callable
                $this->_providers[$id] = $provider;
            } elseif (is_array($provider)) {
                // a configuration array
                if (isset($provider['__class'])) {
                    $this->_providers[$id] = $provider;
                    $this->_providers[$id]['class'] = $provider['__class'];
                    unset($this->_providers[$id]['__class']);
                } elseif (isset($provider['class'])) {
                    $this->_providers[$id] = $provider;
                } else {
                    throw new InvalidConfigException('服务 `' . $id . '` 的配置必须包含 `class` 元素');
                }
            } else {
                throw new InvalidConfigException('服务 `' . $id . '` 的配置无效');
            }
        }
    }

    /**
     * @param string $name
     * @return Service
     * @throws InvalidConfigException
     * @throws \yii\base\UnknownPropertyException
     */
    public function __get($name)
    {
        if (isset($this->_services[$name])) {
            return $this->_services[$name];
        }

        if (isset($this->_providers[$name])) {
            $provider = $this->_providers[$name];
            if (is_object($provider) && !$provider instanceof \Closure) {
                return $this->_services[$name] = $provider;
            }
            return $this->_services[$name] = Yii::createObject($provider);
        }

        return parent::__get($name);
    }
}